package com.lottery.common.singleton;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lottery.common.entity.FilterWord;
import com.lottery.common.service.FilterWordService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.nutz.lang.util.NutMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

/**
 * Created by jpzhang on 2017/1/9.
 * 敏感词过滤器
 */
@Slf4j
@Service
public class SensitiveWordFilter {
    public static final Logger logger = LoggerFactory.getLogger(SensitiveWordFilter.class);
    private static SensitiveWordFilter instance = null;
    public HashMap dataMap;
    private MatchingType matchingType;
    private static final String REPLACE_CHAR = "*";

    /**
     * 匹配类型，目前支持最小匹配规则和最大匹配规则
     */
    public static enum MatchingType {
        MIN, MAX
    }


    private SensitiveWordFilter() {
        matchingType = MatchingType.MIN;

    }

    @Autowired
    private FilterWordService filterWordService;

    @PostConstruct
    public void init() {
        log.info("init redisTemplate");
//        QueryWrapper<FilterWord> queryWrapper=new QueryWrapper<>();
//        queryWrapper.select("word");
//        List<String> list=filterWordService.list(queryWrapper);
        SensitiveWordFilter.getInstance().init(filterWordService.list());
        SensitiveWordFilter.getInstance().setMatchingType(SensitiveWordFilter.MatchingType.MAX);
    }


    public static SensitiveWordFilter getInstance() {
        if (instance == null) {
            instance = new SensitiveWordFilter();
        }
        return instance;
    }

    public void setMatchingType(MatchingType matchingType) {
        this.matchingType = matchingType;
    }


    public static interface DataLoader {
        public List<String> load();
    }

    /**
     * 初始化，构造DFA状态机
     * <p/>
     * 中 = {
     * isEnd = 0
     * 国 = {<br>
     * isEnd = 1
     * 人 = {isEnd = 0
     * 民 = {isEnd = 1}
     * }
     * 男  = {
     * isEnd = 0
     * 人 = {
     * isEnd = 1
     * }
     * }
     * }
     * }
     * 五 = {
     * isEnd = 0
     * 星 = {
     * isEnd = 0
     * 红 = {
     * isEnd = 0
     * 旗 = {
     * isEnd = 1
     * }
     * }
     * }
     * }
     *
     * @param dataLoader
     */
    public void init2(List<String> dataLoader) {
        List<String> words = dataLoader;
        dataMap = new HashMap(words.size());
        HashMap currMap = null;
        HashMap tempMap = null;
        for (String word : words) {
            currMap = dataMap;
            for (int i = 0; i < word.length(); i++) {
                char keyChar = word.charAt(i);
                Object wordMap = currMap.get(keyChar);

                if (wordMap != null) {
                    //如果存在该key，直接赋值
                    currMap = (HashMap) wordMap;
                } else {
                    //不存在则，则构建一个map，同时将isEnd设置为0，因为他不是最后一个
                    tempMap = new HashMap();
                    tempMap.put("isEnd", "0");
                    currMap.put(keyChar, tempMap);
                    currMap = tempMap;
                }
            }
            currMap.put("isEnd", "1");
        }

        logger.info("SensitiveWords.size={}", dataMap.size());

    }

    public void init(List<FilterWord> dataLoader) {
        List<FilterWord> words = dataLoader;
        dataMap = new HashMap(words.size());
        HashMap currMap = null;
        HashMap tempMap = null;
        for (FilterWord word : words) {
            currMap = dataMap;
            for (int i = 0; i < word.getWord().length(); i++) {
                char keyChar = word.getWord().charAt(i);
                Object wordMap = currMap.get(keyChar);

                if (wordMap != null) {
                    //如果存在该key，直接赋值
                    currMap = (HashMap) wordMap;
                } else {
                    //不存在则，则构建一个map，同时将isEnd设置为0，因为他不是最后一个
                    tempMap = new HashMap();
                    tempMap.put("isEnd", "0");
                    currMap.put(keyChar, tempMap);
                    currMap = tempMap;
                }
            }
            currMap.put("isEnd", "1");
        }

        logger.info("SensitiveWords.size={}", dataMap.size());

    }

    /**
     * 执行敏感词替换操作,建议先通过check来判断是否有敏感词，有的话再走替换逻辑
     */
    public String filter(String content) {
        //1.找出所有的敏感词
        List<String> words = new ArrayList<>();
        for (int i = 0; i < content.length(); i++) {
            String word = check0(content, i);
            if (StringUtils.isNotEmpty(word)) {
                words.add(word);
                i = i + word.length() - 1;
            }
        }
        //2.执行过滤操作(长词排前面)
        Collections.sort(words);
        Collections.reverse(words);
        logger.info(words.toString());
        String[] marks = new String[words.size()];
        String[] wordsArray=new String[words.size()];
        for (int i = 0; i < words.size(); i++) {
            wordsArray[i]=words.get(i);
            marks[i] = StringUtils.repeat(REPLACE_CHAR, words.get(i).length());
        }
        content = StringUtils.replaceEachRepeatedly(content, wordsArray,marks);
        return content;
    }

    /**
     * 检测是否包含敏感词
     *
     * @param content
     * @return
     */
    public NutMap check(String content) {
        //长度大于2才需要检测
        NutMap nutMap=new NutMap();
        nutMap.setv("data",false);
        nutMap.setv("word","");
        if (StringUtils.isEmpty(content) || content.length() < 2) {
            return nutMap;
        }
        for (int i = 0; i < content.length(); i++) {
            String word = check0(content, i);
            if (StringUtils.isNotEmpty(word)) {
                logger.info("word={}", word);
                nutMap.setv("data",true);
                nutMap.setv("word",word);
                return nutMap;
            }
        }
        return nutMap;
    }

    /**
     * 从idx开始检测，检测到敏感词，返回敏感词。否则返回空
     *
     * @param content
     * @param idx
     * @return
     */
    private String check0(String content, int idx) {
        StringBuilder builder = new StringBuilder();
        HashMap currMap = dataMap;
        //标识是否已经匹配到一个
        boolean flag = false;
        //记录上次找到的敏感词，如果最大匹配没找到，那就返回第二大的敏感词
        String lastWord=null;
        for (int i = idx; i < content.length(); i++) {
            logger.debug("current word={}", content.charAt(i));
            currMap = (HashMap) currMap.get(content.charAt(i));
            if (currMap == null) {
                break;
            }
            //存在，判断是否最后一个
            builder.append(content.charAt(i));
            if (currMap.get("isEnd").equals("1")) {
                flag = true;
                lastWord=builder.toString();
                if (matchingType == MatchingType.MIN) {
                    break;
                } else {
                    //最大匹配接着往后走

                }

            }

        }
        if (!flag) {
            return null;
        }
        return lastWord;
    }


}
